package com.hsmpay.qian4.service.ds.impl;

import com.hsmpay.common.pojo.qian4.Qian4SendLog;
import com.hsmpay.common.pojo.user.User;
import com.hsmpay.common.util.NumberUtil;
import com.hsmpay.mobile.action.account.scanCodePay.MD5;
import com.hsmpay.mobile.action.account.scanCodePay.ScanCodePayParam;
import com.hsmpay.mobile.action.account.scanCodePay.SignUtils;
import com.hsmpay.mobile.action.account.scanCodePay.XmlUtils;
import com.hsmpay.mobile.pojo.trans.TransPriorSettle;
import com.hsmpay.mobile.service.trans.TransPriorSettleService;
import com.hsmpay.mobile.service.user.UserService;
import com.hsmpay.qian4.pojo.PurchaseResult;
import com.hsmpay.qian4.pojo.RevocationResult;
import com.hsmpay.qian4.service.ds.ShangLianChuPayService;
import com.hsmpay.utils.DesUtil;
import com.hsmpay.utils.WriteFile;
import com.hsmpay.utils.system.ConConfig;

import javapns.org.json.JSONException;
import javapns.org.json.JSONObject;

import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service("shangLianChuService")
public class ShangLianChuServiceImpl implements ShangLianChuPayService{

    public static WriteFile wf = new WriteFile("ds_JQScan");
    private Logger log = LoggerFactory.getLogger(this.getClass());
    private static final String version = "1.0.0";
    public static final  String submchid = "1391963502";
    private static final String MD5Key = "4683462567867C6120A251F8A1B0D6A1";
    private static final String signType = "MD5";
    
    public static String urlStr = ConConfig.getAttribute("URL_OFFICIAL");
    public static String organizationId = ConConfig.getAttribute("SLC_ORGANIZATION_ID");
    public static String slcKey = ConConfig.getAttribute("SLC_KEY");

    @Resource(name = "transPriorSettleService")
    private TransPriorSettleService<TransPriorSettle, Long> transPriorSettleService;
    @Resource(name = "userService")
    protected UserService<User, Long> userService;
    
    static int CashMoneyFee = Integer.parseInt(ConConfig.getAttribute("CASH_MONEY_FEE"));

    
    
    /**
     * 商联储公众号支付
     * @param send
     * @return
     * @throws Exception
     */
    public PurchaseResult getQRCode(Qian4SendLog send, ScanCodePayParam scanCodePayParam, String signatureRelPath) throws Exception {
    	 //通知地址http://weixin.zhijianzhuan.com.cn/proOneMobile/scanPay/scanPayNL_SlcNotify.action
        String notify_url = "http://"+urlStr+"/proOneMobile/scanPay/scanPayNL_SlcNotify.action";
        String callback_url = "http://"+urlStr+"/proOneMobile/user/weixinPaySuccess.action";
        //String reqUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //公众账号ID	
        //String appid = appid;
        //商户号
       // String mch_id = "1384671002";
        //设备号
        //随机字符串
        //String nonce_str = NumberUtil.generateRandomString(32);
        //商品描述
        String body= scanCodePayParam.getBody();
        //商户系统内部的订单号,32个字符内
        String out_trade_no = scanCodePayParam.getOutTradeNo();
        //总金额
        double totalFee = Double.valueOf(scanCodePayParam.getTotalFee());
        int total_fee = NumberUtil.roundF2(totalFee*100).intValue();
        //用户标识
        String openid= scanCodePayParam.getSubOpenId();
        //签名
        //String sign = "";
      
        wf.log("【商联储-收款 请求参数】outTradeNo: "+out_trade_no, "调试");
        wf.log("【商联储-收款 请求参数】totalFee: "+total_fee, "调试");
        wf.log("【商联储-收款 请求参数】openid: "+openid, "调试");
        PurchaseResult pr = new PurchaseResult();
        Long userId = send.getUserId();
        User user = userService.getUserById(userId);
        
//        TransPriorSettle transPriorSettle = new TransPriorSettle();
//        transPriorSettle.setOrderNum(out_trade_no);
//        transPriorSettle = transPriorSettleService.searchEntity(transPriorSettle);
//        long transPriorSettleId = transPriorSettle.getId();
        
        if(ConConfig.isFormal()){
            wf.log("【商联储-收款】请求环境:生产环境", "调试");
            try {
            	SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyyMMddHHmmss");
        		Date date = new Date();
        		String sendTime = dateFormat.format(date);
        		dateFormat = new SimpleDateFormat("HHmmssSSS");
        		String sendSeqId = dateFormat.format(date);
            	JSONObject jsonObject = new JSONObject();
        		jsonObject.put("sendTime", sendTime);
        		jsonObject.put("sendSeqId", out_trade_no);
        		jsonObject.put("transType", "B001");
        		jsonObject.put("organizationId", organizationId);
        		jsonObject.put("transAmt", total_fee);
        		jsonObject.put("body", body);
        		jsonObject.put("openId", openid);
        		jsonObject.put("payPass", "1");
        		jsonObject.put("notifyUrl", notify_url);
        		jsonObject.put("callbackUrl", callback_url);
        		jsonObject.put("name",user.getUserName());
        		jsonObject.put("cardNo", user.getBankCard());
        		jsonObject.put("idNum", user.getIdentityCard());
        		//TODO test code lishijie
    		    int cashMoneyFee = (int) (CashMoneyFee * 100 + total_fee * user.getCashRate() + total_fee * user.getFeeRate());//提现手续费
               
        		jsonObject.put("fee", cashMoneyFee);
        		Map<String, String> contentData = (Map<String, String>) parserToMap(jsonObject.toString());
        		String macStr="";
        		Object[] key_arr = contentData.keySet().toArray();
        		Arrays.sort(key_arr);
        		for (Object key : key_arr) {
        			Object value = contentData.get(key);
        			if (value != null ) {
        				if (!key.equals("mac") ) {
        					macStr+= value.toString();
        				}
        			}
        		}
        		
        		String mac = getMD5Str(macStr + slcKey);
        		jsonObject.put("mac", mac);
        		
        		String data = jsonObject.toString();
        		
        		log.info("请示数据为:{}",data);
        		
        	
        		
        		//XXX 成功没有值，失败有值
        		if(StringUtils.isNotEmpty(data)){
        			pr.setNonceStr(notify_url);
        			pr.setPaySign(data);
    				pr.setResultCode("0000");
    				pr.setReqMsg("获取交易成功!");
    				pr.setReqCode("0000");
        		}else{
        			pr.setResultCode("9999");
    				pr.setReqMsg("获取交易失败!");
    				pr.setReqCode("9999");
        		}
        		
        		
//            	PublicScanPayReqData scanPayReqData = new PublicScanPayReqData(openid,submchid,notify_url,trade_type, body, "", out_trade_no, total_fee, device_info, spbill_create_ip, "", "", "");
//            	String info = WXPay.requestScanPayService(scanPayReqData);
//            	log.info("商联储返回的信息："+info);
//            	resultMap = XMLParser.getMapFromXML(info);
            }catch (Exception e){
                e.printStackTrace();
                log.error("【商联储-收款】 系统异常!");
            }
        }else{
        	//XXX 测试环境直接返回
        }

   
        return pr;
    }
    
    private  String getSign(String appId,String timeStamp,String nonceStr,String prepay_id,String signType,String key){
    	 Map<String, String> map =  new HashMap<String, String>();
    	 map.put("appId", appId);
    	 map.put("timeStamp", timeStamp);
    	 map.put("nonceStr", nonceStr);
    	 map.put("package", "prepay_id="+prepay_id);
    	 map.put("signType", signType);
    	 Map<String,String> params = SignUtils.paraFilter(map);
         StringBuilder buf = new StringBuilder((params.size() +1) * 10);
         SignUtils.buildPayParams(buf,params,false);
         String preStr = buf.toString();
         String sign = MD5.sign(preStr, "&key=" + key, "utf-8");
         return sign;
    }
    

    /**
     * 冲正
     * @param out_trade_no 商户系统内部订单号
     * @return
     * @throws Exception
     */
    public RevocationResult revocation(String out_trade_no)throws Exception {

        String reqUrl = "https://pay.swiftpass.cn/pay/gateway";
        String service = "unified.micropay.reverse";

        log.error("【商联储-冲正 请求参数】out_trade_no: " + out_trade_no);
        wf.log("【商联储-冲正 请求参数】out_trade_no: " + out_trade_no, "调试");

        String nonceStr = DesUtil.generate32Key();

        SortedMap<String,String> map = new TreeMap<>();
        map.put("service", service);
        map.put("version", version);
        map.put("sign_type", signType);
        map.put("mch_id", submchid);
        map.put("nonce_str", nonceStr);
        map.put("out_trade_no",out_trade_no);

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + MD5Key, "utf-8");

        map.put("sign",sign);

        log.error("【商联储-冲正 请求参数】:" + XmlUtils.parseXML(map));

        Map<String, String> resultMap = new HashedMap();
        if(ConConfig.isFormal()){
            CloseableHttpResponse response = null;
            CloseableHttpClient client = null;
            try {
                HttpPost httpPost = new HttpPost(reqUrl);
                StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8");
                httpPost.setEntity(entityParams);
                httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
                client = HttpClients.createDefault();
                response = client.execute(httpPost);
                if (response != null && response.getEntity() != null) {
                    resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("【商联储-冲正】 系统异常!");
            }
        }else {
            //TODO:补充范例
            resultMap = null;
        }

        log.error("【商联储-冲正 响应参数】:" + XmlUtils.toXml(resultMap));

        RevocationResult rr = new RevocationResult();
        rr.setReqCode("0001");
        rr.setReqMsg("交易撤消失败!");
        rr.setStatus(0);

        if(resultMap.isEmpty()){
            rr.setReqMsg("操作失败,系统未响应!");
            return rr;
        }

        //校验签名
        if(resultMap.containsKey("sign")){
            if(!SignUtils.checkParam(resultMap, MD5Key)) {
                rr.setReqMsg("验证签名不通过!");
                return rr;
            }
        }

        String status = resultMap.get("status");
        String message = resultMap.get("message");

        if(StringUtils.isNotBlank(message)){
            rr.setReqMsg(message);
            return rr;
        }

        if(status.equals("0")){
            String result_code  = resultMap.get("result_code");
            if(result_code.equals("0")){
                rr.setReqCode("0000");
                rr.setReqMsg("交易撤消成功!");
                rr.setStatus(1);
            }
        }else {
            String err_code = resultMap.get("err_code");
            rr.setReqMsg(err_code);
        }
        return rr;
    }


    /**
     * 查询交易订单
     * @param out_trade_no 商户系统内部订单号
     * @return RevocationResult
     * @throws Exception
     */
    public RevocationResult queryorder(String out_trade_no)throws Exception {

        String reqUrl = "url:https://pay.swiftpass.cn/pay/gateway";
        String service = "unified.trade.query";

        log.error("【商联储-查询 请求参数】out_trade_no: " + out_trade_no);
        wf.log("【商联储-查询 请求参数】out_trade_no: " + out_trade_no, "调试");

        String nonceStr = DesUtil.generate32Key();

        SortedMap<String,String> map = new TreeMap<>();
        map.put("service", service);
        map.put("version", version);
        map.put("sign_type", signType);
        map.put("mch_id", submchid);
        map.put("nonce_str", nonceStr);
        map.put("out_trade_no",out_trade_no);

        Map<String,String> params = SignUtils.paraFilter(map);
        StringBuilder buf = new StringBuilder((params.size() +1) * 10);
        SignUtils.buildPayParams(buf,params,false);
        String preStr = buf.toString();
        String sign = MD5.sign(preStr, "&key=" + MD5Key, "utf-8");

        map.put("sign",sign);
        log.error("【商联储-查询 请求参数】:" + XmlUtils.parseXML(map));

        Map<String, String> resultMap = new HashedMap();

        if(ConConfig.isFormal()){
            CloseableHttpResponse response = null;
            CloseableHttpClient client = null;
            try {
                HttpPost httpPost = new HttpPost(reqUrl);
                StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8");
                httpPost.setEntity(entityParams);
                httpPost.setHeader("Content-Type", "text/xml;charset=ISO-8859-1");
                client = HttpClients.createDefault();
                response = client.execute(httpPost);
                if (response != null && response.getEntity() != null) {
                    resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.error("商联储-订单查询】 请求时系统异常!");
            }
        }else {
            resultMap = null;
        }

        log.error("【商联储-查询 响应参数】:" + XmlUtils.toXml(resultMap));

        RevocationResult rr = new RevocationResult();
        rr.setReqCode("0001");
        rr.setReqMsg("查询交易订单失败!");
        rr.setStatus(0);

        if(resultMap.isEmpty()){
            rr.setReqMsg("操作失败,系统未响应!");
            return rr;
        }

        //校验签名
        if(resultMap.containsKey("sign")){
            if(!SignUtils.checkParam(resultMap, MD5Key)) {
                rr.setReqMsg("验证签名不通过!");
                return rr;
            }
        }

        String status = resultMap.get("status");
        String message = resultMap.get("message");

        if(status.equals("0")){
            String result_code = resultMap.get("result_code");
            if(result_code.equals("0")){
                String trade_state = resultMap.get("trade_states");
                if(trade_state.equals("SUCCESS")){
                    rr.setReqCode("0000");
                    rr.setReqMsg("交易成功!");
                    rr.setStatus(1);
                }else if(trade_state.equals("NOTPAY")){
                    rr.setReqCode("0002");
                    rr.setReqMsg("交易失败,请确认是否输入支付密码 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("CLOSED")){
                    rr.setReqCode("0003");
                    rr.setReqMsg("交易已关闭 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("REVOKED") || trade_state.equals("REFUND")){
                    rr.setReqCode("0004");
                    rr.setReqMsg("交易已撤销 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("PAYERROR")){
                    rr.setReqCode("0001");
                    rr.setReqMsg("交易失败 !");
                    rr.setStatus(0);
                }else if(trade_state.equals("USERPAYING")){
                    rr.setReqCode("0005");
                    rr.setReqMsg("用户交易中!");
                    rr.setStatus(0);
                }
            }else {
                String err_msg = resultMap.get("err_msg");
                String err_code = resultMap.get("err_code");
                rr.setReqMsg(err_msg);
                rr.setReqCode(err_code);
            }
        }else {
            rr.setReqMsg(message);
        }
        return rr;
    }
    public static String getMD5Str(String str) {

		MessageDigest messageDigest = null;

		try {

			messageDigest = MessageDigest.getInstance("MD5");

			messageDigest.reset();

			messageDigest.update(str.getBytes("UTF-8"));

		} catch (NoSuchAlgorithmException e) {

			System.out.println("NoSuchAlgorithmException caught!");

			System.exit(-1);

		} catch (UnsupportedEncodingException e) {

			e.printStackTrace();

		}

		byte[] byteArray = messageDigest.digest();

		StringBuffer md5StrBuff = new StringBuffer();

		for (int i = 0; i < byteArray.length; i++) {

			if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
				md5StrBuff.append("0").append(
						Integer.toHexString(0xFF & byteArray[i]));
			else
				md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));

		}
		return md5StrBuff.toString();
	}
	
	public static HashMap<String, String> parserToMap(String s){  
	    Map map=new HashMap();  
	    JSONObject json;
		try {
			json = new JSONObject(s);
			Iterator keys=json.keys();  
		    while(keys.hasNext()){  
		        String key=(String) keys.next();  
		        String value=json.get(key).toString();    
		        map.put(key, value); 
		    }  
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    return (HashMap<String, String>)map;  
	}
}
